Skip to contentMethod: ContextBuildingJsonLdSerializer(JsonGenerator, Configuration)
1: /*
2: * JB4JSON-LD
3: * Copyright (C) 2023 Czech Technical University in Prague
4: *
5: * This library is free software; you can redistribute it and/or
6: * modify it under the terms of the GNU Lesser General Public
7: * License as published by the Free Software Foundation; either
8: * version 3.0 of the License, or (at your option) any later version.
9: *
10: * This library is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13: * Lesser General Public License for more details.
14: *
15: * You should have received a copy of the GNU Lesser General Public
16: * License along with this library.
17: */
18: package cz.cvut.kbss.jsonld.serialization;
19:
20: import cz.cvut.kbss.jopa.model.MultilingualString;
21: import cz.cvut.kbss.jsonld.ConfigParam;
22: import cz.cvut.kbss.jsonld.Configuration;
23: import cz.cvut.kbss.jsonld.JsonLd;
24: import cz.cvut.kbss.jsonld.exception.AmbiguousTermMappingException;
25: import cz.cvut.kbss.jsonld.serialization.context.JsonLdContext;
26: import cz.cvut.kbss.jsonld.serialization.context.JsonLdContextFactory;
27: import cz.cvut.kbss.jsonld.serialization.context.MappingJsonLdContextFactory;
28: import cz.cvut.kbss.jsonld.serialization.model.CollectionNode;
29: import cz.cvut.kbss.jsonld.serialization.model.CompositeNode;
30: import cz.cvut.kbss.jsonld.serialization.model.JsonNode;
31: import cz.cvut.kbss.jsonld.serialization.model.ObjectNode;
32: import cz.cvut.kbss.jsonld.serialization.serializer.LiteralValueSerializers;
33: import cz.cvut.kbss.jsonld.serialization.serializer.ObjectGraphValueSerializers;
34: import cz.cvut.kbss.jsonld.serialization.serializer.ValueSerializer;
35: import cz.cvut.kbss.jsonld.serialization.serializer.ValueSerializers;
36: import cz.cvut.kbss.jsonld.serialization.serializer.context.*;
37: import cz.cvut.kbss.jsonld.serialization.serializer.context.datetime.ContextBuildingTemporalAmountSerializer;
38: import cz.cvut.kbss.jsonld.serialization.serializer.context.datetime.ContextBuildingTemporalSerializer;
39: import cz.cvut.kbss.jsonld.serialization.serializer.datetime.DateSerializer;
40: import cz.cvut.kbss.jsonld.serialization.traversal.ObjectGraphTraverser;
41: import cz.cvut.kbss.jsonld.serialization.traversal.SerializationContextFactory;
42:
43: import java.time.*;
44: import java.util.Collection;
45: import java.util.Date;
46: import java.util.Optional;
47:
48: /**
49: * JSON-LD serializer outputting compacted JSON-LD with context.
50: */
51: public class ContextBuildingJsonLdSerializer extends JsonLdSerializer {
52:
53: ContextBuildingJsonLdSerializer(JsonGenerator jsonGenerator) {
54: super(jsonGenerator);
55: }
56:
57: ContextBuildingJsonLdSerializer(JsonGenerator jsonGenerator, Configuration configuration) {
58: super(jsonGenerator, configuration);
59: }
60:
61: @Override
62: protected ValueSerializers initSerializers() {
63: final ValueSerializer<MultilingualString> mlsSerializer = new ContextBuildingMultilingualStringSerializer();
64: final ValueSerializer<Collection<MultilingualString>> mlsColSerializer =
65: new ContextBuildingPluralMultilingualStringSerializer();
66: final LiteralValueSerializers valueSerializers =
67: new LiteralValueSerializers(new ContextBuildingDefaultValueSerializer(mlsSerializer, mlsColSerializer));
68: valueSerializers.registerIdentifierSerializer(new ContextBuildingIdentifierSerializer());
69: valueSerializers.registerTypesSerializer(new ContextBuildingTypesSerializer());
70: valueSerializers.registerIndividualSerializer(new ContextBuildingIndividualSerializer());
71: final ContextBuildingTemporalSerializer ts = new ContextBuildingTemporalSerializer();
72: valueSerializers.registerSerializer(LocalDate.class, ts);
73: // Register the same temporal serializer for each of the types it supports (needed for key-based map access)
74: valueSerializers.registerSerializer(LocalDate.class, ts);
75: valueSerializers.registerSerializer(LocalTime.class, ts);
76: valueSerializers.registerSerializer(OffsetTime.class, ts);
77: valueSerializers.registerSerializer(LocalDateTime.class, ts);
78: valueSerializers.registerSerializer(OffsetDateTime.class, ts);
79: valueSerializers.registerSerializer(ZonedDateTime.class, ts);
80: valueSerializers.registerSerializer(Instant.class, ts);
81: valueSerializers.registerSerializer(Date.class, new DateSerializer(ts));
82: final ContextBuildingTemporalAmountSerializer tas = new ContextBuildingTemporalAmountSerializer();
83: valueSerializers.registerSerializer(Duration.class, tas);
84: valueSerializers.registerSerializer(Period.class, tas);
85: return valueSerializers;
86: }
87:
88: @Override
89: protected JsonNode buildJsonTree(Object root) {
90: final JsonLdContextFactory jsonLdContextFactory = new MappingJsonLdContextFactory();
91: final JsonLdContext rootContext = jsonLdContextFactory.createJsonLdContext();
92: final ObjectGraphTraverser traverser =
93: new ObjectGraphTraverser(new SerializationContextFactory(rootContext));
94: traverser.setRequireId(configuration().is(ConfigParam.REQUIRE_ID));
95: if (root instanceof Collection) {
96: return buildObjectWithContextAndGraph(traverser, rootContext, jsonLdContextFactory, (Collection<?>) root);
97: }
98: final JsonLdTreeBuilder treeBuilder = initTreeBuilder(traverser, jsonLdContextFactory);
99: traverser.setVisitor(treeBuilder);
100: traverser.traverse(root);
101: ensureContextNodeNotPresent(treeBuilder.getTreeRoot(), rootContext.getContextNode());
102: treeBuilder.getTreeRoot().prependItem(rootContext.getContextNode());
103: return treeBuilder.getTreeRoot();
104: }
105:
106: private void ensureContextNodeNotPresent(CompositeNode<?> root, JsonNode rootCtx) {
107: final Optional<JsonNode> ctxNode =
108: root.getItems().stream().filter(n -> JsonLd.CONTEXT.equals(n.getName())).findAny();
109: if (ctxNode.isPresent()) {
110: throw new AmbiguousTermMappingException(
111: "Unable to build context hierarchy. Attempted to add two root contexts. Original root context: " + rootCtx + ", conflicting: " + ctxNode.get());
112: }
113: }
114:
115: private JsonLdTreeBuilder initTreeBuilder(ObjectGraphTraverser traverser,
116: JsonLdContextFactory jsonLdContextFactory) {
117: final ContextBuildingObjectPropertyValueSerializer opSerializer = new ContextBuildingObjectPropertyValueSerializer(traverser);
118: opSerializer.configure(configuration());
119: return new JsonLdTreeBuilder(new ObjectGraphValueSerializers(serializers, opSerializer), jsonLdContextFactory);
120: }
121:
122: private JsonNode buildObjectWithContextAndGraph(ObjectGraphTraverser traverser, JsonLdContext rootContext,
123: JsonLdContextFactory jsonLdContextFactory,
124: Collection<?> items) {
125: final CollectionNode<?> graph = JsonNodeFactory.createCollectionNodeFromArray(JsonLd.GRAPH);
126: items.stream().map(item -> {
127: final JsonLdTreeBuilder treeBuilder = initTreeBuilder(traverser, jsonLdContextFactory);
128: traverser.setVisitor(treeBuilder);
129: traverser.traverse(item);
130: return treeBuilder.getTreeRoot();
131: }).forEach(graph::addItem);
132: final ObjectNode result = JsonNodeFactory.createObjectNode();
133: result.addItem(rootContext.getContextNode());
134: result.addItem(graph);
135: return result;
136: }
137: }